﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace ProjectFinal {
	static public class Constants {
		public const string PATRON_FILENAME = "patrons.xml";	//Filename for the patron class data
		public const string MEDIA_FILENAME = "media.xml";			//Filename for the media classes data
		public const int ADULT_MAX = 6;												//Number of items an Adult can check out
		public const int CHILD_MAX = 3;												//Number of items a Child can check out
		public const int LOANTIME_ADULT_BOOK = 14;						//Time, in days, an Adult's book can be checked out
		public const int LOANTIME_CHILD_BOOK = 7;							//Time, in days, a Children's book can be checked out
		public const int LOANTIME_DVD = 2;										//Time, in days, a DVD can be checked out
		public const int LOANTIME_VHS = 3;										//Time, in days, a videotape can be checked out (Betamax be damned)
		public const string DATE_FORMAT = "MM/dd/yyyy";				//Format string for Date
	}//class Constants

	static public class BusinessRules {
		static private BindingList<Patron> _patronList = new BindingList<Patron>();	//List of all patrons
		static private BindingList<Item> _itemList = new BindingList<Item>();				//List of all books
		static private Date _today;																									//Today's date
		static private PatronIDAssigner _IDNums;																		//Patron ID number factory
		static private List<Item> _itemCart = new List<Item>();											//list for checkout cart
		static private List<Item> _itemsAvailable = new List<Item>();								//list of Available Items

		//Initialize settigns and use FileIO class to read all patrons and media
		//Param:	today's date
		static public void init(string today) {
			FileIO.patronFilename = Constants.PATRON_FILENAME;
			FileIO.mediaFilename = Constants.MEDIA_FILENAME;
			_IDNums = new PatronIDAssigner(FileIO.loadPatrons(ref _patronList));
			FileIO.loadMedia(ref _itemList);
			_today = new Date(today);
		}//init()

		//Use FileIO class to save all patrons and media
		//note:		if something goes wrong, it gives the option to try to save again
		//					(in case you want to rearrange files or something)
		static public void saveData() {
			bool loop = false; //Assume there's no reason to loop

			do {
				try {
					//Save all data
					FileIO.savePatrons(_patronList);	
					FileIO.saveMedia(_itemList);
				} catch(System.Exception e) {
					//Allow user to decide to try again.  Clicking Yes will loop, clicking No won't
					loop =
							MessageBox.Show(e.Message + "\nReattempt?",
							"Error",
							MessageBoxButtons.YesNo,
							MessageBoxIcon.Exclamation)
								== DialogResult.Yes;
				}
			} while(loop);
		}//saveData()

		//Current date functions
		static public void setToday(string d) { _today = new Date(d); }		//Set Today's date
		static public void setToTomorrow() { _today.beTomorrow(); }				//Change Today to Tomorrow's date
		static public DateTime getTodayDT() { return _today.getDate(); }	//Get Today's date
		static public Date getToday() { return _today; }									//ibid.

		//Give an Item to a Patron for checkout
		//Param:	Patron to give item, Item to check out
		//Post:		Returns True if checkout is successful, False otherwise
		static public Boolean checkOut(Patron p, Item i) { return p.checkOutItem(i, _today); }

		//Clear shopping cart
		static public void clearCart() { _itemCart.Clear(); }

		//Check in an Item
		//Param:	Patron that had item, Item to check in
		static public void checkIn(Patron p, Book b) { p.checkInItem(b); }
		static public void checkIn(Patron p, Media m) { p.checkInItem(m); }

		//Populate the listbox with all items
		//Param:	listbox to populate
		static public void listItems(ListBox list) {
			list.Items.Clear();
			_itemsAvailable.Clear();

			//add itms to available list
			foreach(Item i in _itemList)
				if(i.isCheckedIn() && !_itemCart.Contains(i))
					_itemsAvailable.Add(i);
				
			foreach(Item j in _itemsAvailable)
				list.Items.Add(j.Title);
		}//void listItems(ListBox)

		//Populate the listbox with childrens books
		//Param:	listbox to populate
		static public void listChildrensBooks(ListBox list) {
			list.Items.Clear();
			_itemsAvailable.Clear();
			foreach(Item b in _itemList) 
				if(b.isCheckedIn() && !_itemCart.Contains(b))
					if(b.getType() == MediaType.childBook) {
						_itemsAvailable.Add(b);
						list.Items.Add(b.Title);
					}
		}//void listChildrensBooks(ListBox list)

		//Populate the listbox with all patrons
		//Param:	listbox to populate
		static public void listPatrons(ListBox list) {
			list.Items.Clear();
			foreach(Patron p in _patronList)
				list.Items.Add(p.Name);
		}//void listPatrons(ListBox)

		//Find book by index within the shopping cart
		//Param:	cart index
		//Pre:		index must be within range
		//Post:		returns Item at given index
		//				returns null if index is not within range
		static public Item getItemCartInfo(int index) {
			if(index < 0 || index >= _itemCart.Count)
				return null;
			return _itemCart[index]; 
		}//Item getItemCartInfo(int)

		//Find patron by index within the patron list
		//param:	patron list index
		//Pre:		index must be within range
		//Post:		returns Patron at given index
		//				returns null if index is not within range
		static public Patron getPatronInfo(int index) {
			if(index < 0 || index >= _patronList.Count)
				return null;
			return _patronList[index]; 
		}//Patron getPatronInfo(int)

		//Find patron by ID
		//Param:	ID#
		//Post:		Returns Patron with given ID
		//				returns null if there is no Patron with the given ID
		static public Patron getPatronByID(int id) {
			foreach(Patron p in _patronList)
				if(p.ID == id)
					return p;
			return null;
		}//Patron getPatronByID(int)

		//Create a new patron and add it to the list
		//Param:	Name, Adult status
		static public void newPatron(string name, bool isAdult) {
			_patronList.Add(new Patron(name, _IDNums.newPatronID(), isAdult));
		}//void addPatron(string, bool)

		//Create a new book and add it to the list
		//Param:	Name, Author, ID Code, book type
		static public void newBook(string title, string author, string bookID, MediaType type) {
			_itemList.Add(new Book(title, author, bookID, type));
		}//void newBook(string, string, string, MediaType)

		//Create a new Movie and add it to the list
		//Param:	Name, ID Code, Movie type
		static public void newMedia(string title, string ID, MediaType type) {
			_itemList.Add(new Media(title, ID, type));
		}//void newBook(string, string, string, MediaType)

		//Remove a Patron from the list
		//Param:	ID number of Patron to remove
		//Post:		Patron is removed from the list.
		//				Nothing happens if ID number isn't found.
		//				It is assumed that IDs are unique--operation stops once an ID is found
		static public void removePatron(int id) {
			for(int i = 0; i < _patronList.Count(); ++i)
				if(_patronList[i].ID == id) {
					_patronList.RemoveAt(i);
					break;
				}
		}//void removePatron(int)

		//Remove an Item from the list
		//Param:	ID of the Item to remove
		//Post:		Item is removed.  If there is no Item with the ID, nothing happens
		//				It is assumed that IDs are unique--operation stops once an ID is found
		static public void removeItem(string id) {
			for(int i = 0; i < _itemList.Count(); ++i)
				if(_itemList[i].ID == id) {
					_itemList.RemoveAt(i);
					break;
				}
		}//void removeItem(string)

		//Get a list with the items a Patron has checked out
		//Param:	index within patron list
		//Pre:		index must be within the range of the list
		//Post:		Creates and returns a list with each Item the Patron has checked out
		//				returns null if index is out of range
		static public List<Item> getPatronItemList(int index) {
			if(index < 0 || index >= _patronList.Count)
				return null;

			List<String> temp = _patronList[index].getItems();
			List<Item> tempItems = new List<Item>();
			foreach(String s in temp) {
				foreach(Item i in _itemList) {
					if(i.ID == s)
						tempItems.Add(i);
				}
			}
			return tempItems;
		}//List<Item> getPatronItemList(int)

		//List patron items that are currently checked out in a listbox
		//Pre:		index must be within the range of the list
		//Param:	Listbox to populate, index within patron list
		//				no-op if index is out of range
		static public void listPatronItems(ListBox list, int index) {
			if(index < 0 || index >= _patronList.Count)
				return;

			list.Items.Clear();
			List<String> temp = _patronList[index].getItems();
			List<Item> tempItems = new List<Item>();
			foreach(String s in temp) {
				foreach(Item i in _itemList) {
					if(i.ID == s)
						tempItems.Add(i);
				}
			}
			String title;
			foreach(Item i in tempItems) {
				title = i.Title;
				if(title.Length > 55)//otherwise it will not fit in the title section of the listbox
                {
					title = title.Substring(0, 55);
					title += "...";
				}

				list.Items.Add(title + "\t" + i.ID + "\t" + i.Duedate.ToString());
			}
		}//void listPatronItems(ListBox list, int index)

		//Get patron checkout limit
		//param: int index for list
		//pre:		index must be within range
		//post:		returns maximum number of items patron can check out
		//				returns 0 if index is out of range
		static public int patronLimit(int index) {
			if(index < 0 || index >= _patronList.Count)
				return 0;

			return _patronList[index].getMaxItems();
		}//int patronLimit(int index)

		//Get patron checkout limit
		//param: int index for list
		//pre:		index must be within range
		//post:		returns number of remaining items patron can check out
		//				returns 0 if index is out of range
		static public int patronItemsLeft(int index) {
			if(index < 0 || index >= _patronList.Count)
				return 0;

			return _patronList[index].getMaxItems() - _patronList[index].totalItems();
		}//int patronItemsLeft(int index)

		//For use with data grid
		static public BindingList<Item> getItemList() { return _itemList; }

		//For use with the Patron List
		static public BindingList<Patron> getPatronList() { return _patronList; }

		//adds an Item to the checkout cart
		static public void addItemToCart(ListBox cart, ListBox available, int index) {
			if(index != -1) {
				if(!_itemCart.Contains(_itemsAvailable[index])) {
					//add to cart
					_itemCart.Add(_itemsAvailable[index]);
					cart.Items.Add(_itemsAvailable[index].Title);
					//remove from available list
					_itemsAvailable.RemoveAt(index);
					available.Items.RemoveAt(index);
				}
			}
		}//void addItemToCart(ListBox list, int index)

		//displays detailed item info
		//Param:	Text Box in which to display data, index of item
		//pre:		index must be within range
		//				no-op if index is out of range
		static public void displayItemInfo(RichTextBox text, int index) {
			if(index < 0 || index >= _itemsAvailable.Count)
				return;

			Book b;
			Media m;
			String t;
			String format;
			String type;
		
			//reset box
			text.Clear();

			if(_itemsAvailable[index] is Book) {
				b = (Book)_itemsAvailable[index];

				if(b.getType() == MediaType.adultBook)
					type = "Adult Book";
				else
					type = "Child Book";

				t = "Title: {0} \n\nAuthor: {1}\n\nCall Number: {2}\n\nType: {3}\n\nStatus: Available";

				format = String.Format(t, b.Title, b.Author, b.ID, type);
			} else {
				m = (Media)_itemsAvailable[index];

				if(m.getType() == MediaType.DVD)
					type = "DVD";
				else
					type = "VHS";

				t = "Title: {0} \n\nCall Number: {1}\n\nType: {2}\n\nStatus: Available";
				format = String.Format(t, m.Title, m.ID, type);
			}
			text.Text = format;
		}//void displayItemInfo(RichTextBox text, int index)

		//removes an item from the checkout cart
		//Param:	Cart listbox, Available Items listbox, index within cart
		//pre:		index must be within range
		//				no-op if index is out of range
		static public void removeItemFromCart(ListBox cart, ListBox available, int index) {
			if(index < 0 || index >= _itemCart.Count)
				return;
			//remove from cart list
			_itemCart.RemoveAt(index);
			//remove from cart display
			cart.Items.RemoveAt(index);
			//Update available list
			listItems(available);
		}//void removeItemFromCart(ListBox, ListBox, int)

		//Get an item by ID Code
		//param:	item ID
		//Post:		Associated item is returned
		//				returns null if there isn't one by that ID
		static public Item getSpecificItem(String id) {
			foreach(Item i in _itemList)
				if(i.ID == id)
					return i;

			return null;//If the media isn't found
		}//Item getSpecificItem(string)

		//Sort the Patrons
		//Post:	Patrons are sorted in ascending alphabetical order
		static public void sortPatrons() {
			//Implement a quick bubble sort
			//	(back to front since most sorting is just placing a new item in its proper location)
			bool changed = false;
			for(int i = 0; i < _patronList.Count(); ++i) {
				for(int j = _patronList.Count() - 1; j > i; --j)
					if(string.Compare(_patronList[j].Name, _patronList[j - 1].Name, true) < 0) {
						//Seriously, why don't these Generic Containers have sort or swap methods already?!
						Patron temp = _patronList[j];
						_patronList[j] = _patronList[j - 1];
						_patronList[j - 1] = temp;
						changed = true;
					}
				if(!changed) break;
			}
		}//void sortPatrons()

		//Sort the Items
		//Post:	Items are sorted in ascending alphabetical order
		static public void sortItems() {
			//Implement a quick bubble sort
			//	(back to front since most sorting is just placing a new item in its proper location)
			bool changed = false;
			for(int i = 0; i < _itemList.Count(); ++i) {
				for(int j = _itemList.Count() - 1; j > i; --j)
					if(string.Compare(_itemList[j].Title, _itemList[j - 1].Title, true) < 0) {
						//Seriously, why don't these Generic Containers have sort or swap methods already?!
						Item temp = _itemList[j];
						_itemList[j] = _itemList[j - 1];
						_itemList[j - 1] = temp;
						changed = true;
					}
				if(!changed) break;
			}
		}//void sortItems()

		//Search within a listbox for a given string
		//Param:	Listbox, search string
		//Post:		Updates Available items list with search results
		static public void search(ListBox list, String s) {
			list.Items.Clear();
			_itemsAvailable.Clear();
			foreach(Item i in _itemList) {
				if(i.isCheckedIn() && !_itemCart.Contains(i)) {
					if(s == "") {
						_itemsAvailable.Add(i);
						list.Items.Add(i.Title);
					} else if(i.Title.ToLower().Contains(s.ToLower())) {
						_itemsAvailable.Add(i);
						list.Items.Add(i.Title);
					}
				}
			}
			if(_itemsAvailable.Count == 0)
				MessageBox.Show("No results.", "Search", MessageBoxButtons.OK, MessageBoxIcon.Information);
		}//void search(ListBox, String)

		//Search within a listbox for a given string within the children's books
		//Param:	Listbox, search string
		//Post:		Updates Available items list with search results
		//				Results are restricted to available children's books
		static public void childrensSearch(ListBox list, String s) {
			list.Items.Clear();
			_itemsAvailable.Clear();
			foreach(Item i in _itemList) {
				if(i.isCheckedIn() && !_itemCart.Contains(i)) {
					if(i.getType() == MediaType.childBook) {
						if(s == "") {
							_itemsAvailable.Add(i);
							list.Items.Add(i.Title);
						} else if(i.Title.ToLower().Contains(s.ToLower())) {
							_itemsAvailable.Add(i);
							list.Items.Add(i.Title);
						}
					}
				}
			}
		}//void childrensSearch(ListBox, String)
	}//class BusinessRules
}//namespace
